package cn.com.generaldata.os.dao.impl;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import cn.com.generaldata.os.dao.intf.BaseDAOInterface;
import cn.com.generaldata.os.paging.Event;
import cn.com.generaldata.os.paging.Filter;
import cn.com.generaldata.os.paging.Page;
import cn.com.generaldata.os.paging.Result;
import cn.com.generaldata.os.util.FilterUtils;

public class BaseDAO<T> extends HibernateDaoSupport implements BaseDAOInterface<T> {

	@Override
	public void save(T t) {
		getHibernateTemplate().save(t);
		getHibernateTemplate().flush();
	}

	@Override
	public void merge(T t) {
		getHibernateTemplate().merge(t);
		// getHibernateTemplate().flush();
	}

	@Override
	public void saveOrUpdate(T t) {
		getHibernateTemplate().saveOrUpdate(getHibernateTemplate().merge(t));
		getHibernateTemplate().flush();
	}

	@Override
	public void update(T t) {
		getHibernateTemplate().update(t);
		getHibernateTemplate().flush();
	}

	@Override
	public void delete(T t) {
		getHibernateTemplate().delete(t);
		getHibernateTemplate().flush();
	}

	@Override
	public void delete(List<T> ts) {
		getHibernateTemplate().deleteAll(ts);
		getHibernateTemplate().flush();
	}

	@Override
	public List findByCriteria(DetachedCriteria dc) {
		return this.getHibernateTemplate().findByCriteria(dc);
	}

	@Override
	public List findByCriteriaPage(DetachedCriteria dc, int firstResult, int maxResults) {
		return this.getHibernateTemplate().findByCriteria(dc, firstResult, maxResults);
	}

	@SuppressWarnings("unchecked")
	@Override
	public T get(Class<?> clazz, Serializable id) {
		try {
			return (T) getHibernateTemplate().get(clazz, id);
		} catch (DataAccessException e) {
			// TODO Auto-generated catch block
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> find(Class<?> clazz, Filter filter, Page page) {
		DetachedCriteria criteria = DetachedCriteria.forClass(clazz);

		if (filter != null) {
			criteria = FilterUtils.parseFilter(filter, criteria);
		}

		if (page == null) {
			return getHibernateTemplate().findByCriteria(criteria);
		} else {
			return getHibernateTemplate().findByCriteria(criteria, page.getFirstResult(), page.getPageSize());
		}
	}

	@Override
	public int count(Class<?> clazz, Filter filter) {
		return find(clazz, filter, null).size();
	}

	/**
	 * 　按HQL条件查询列表.
	 * 
	 * @param hql
	 *            查询语句,支持连接查询和多条件查询
	 * @param params
	 *            参数数组,代替hql中的"?"号
	 * @return 结果集List　　
	 */

	@Override
	@SuppressWarnings("unchecked")
	public List<T> findByHql(String hql, Object... params) {
		List list = getHibernateTemplate().find(hql, params);
		return list;
	}

	@Override
	@SuppressWarnings("unchecked")
	public int countByHql(String hql, Object... params) {
		return ((Long) getHibernateTemplate().find(hql, params).listIterator().next()).intValue();
	}

	@Override
	@SuppressWarnings("unchecked")
	public List findByHqlReal(String hql, Object... params) {
		List list = getHibernateTemplate().find(hql, params);
		return list;
	}

	public List<T> find(String hql) {
		HibernateTemplate ht = this.getHibernateTemplate();
		ht.setMaxResults(0);
		return ht.find(hql);
	}

	@Override
	public Result hqlParam(final String hql, final HashMap map, final Page page) {

		// 用回调方法，它会自己管理session
		return (Result) this.getHibernateTemplate().execute(new HibernateCallback<Result>() {
			@Override
			public Result doInHibernate(Session session) throws HibernateException, SQLException {

				Query query = session.createQuery(hql);
				if (map != null) {
					query.setProperties(map);
				}
				String sum = "";
				int fIndex = hql.indexOf("from");
				if (fIndex != -1) {
					sum = "select count(*) as count " + hql.substring(fIndex);
				}
				int oIndex = sum.indexOf("order by");
				if (oIndex != -1) {
					sum = sum.substring(0, oIndex);
				}
				Query querySum = session.createQuery(sum);
				if (map != null) {
					querySum.setProperties(map);
				}
				int count = ((Number) querySum.iterate().next()).intValue();
				if (page == null) {
					query.setFirstResult(0);
					query.setMaxResults(count);
				} else {
					query.setFirstResult(page.getFirstResult());
					query.setMaxResults(page.getPageSize());

				}
				List<T> findByHql = query.list();

				if (page == null) {
					return new Result(1, 1, count, findByHql, new ArrayList<Event>());
				} else {
					return new Result(page.getPageNumber(), page.getPageSize(), count, findByHql, new ArrayList<Event>());
				}
			}
		});
	}

	@Override
	public List findEntitiesByHql(final String hql, final int first, final int max, final Object... params) {
		return (List) this.getHibernateTemplate().execute(new HibernateCallback<List>() {
			@Override
			public List doInHibernate(Session session) throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				if (first > 0) {
					query.setFirstResult(first);
				}
				if (max > 0) {
					query.setMaxResults(max);
				}
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						query.setParameter(i, params[i]);
					}
				}
				return query.list();
			}
		});
	}

	public Integer bulkDelete(final String sql, final Object[] ids) throws Exception {
		// delete xxxx where id in (:ids)
		return this.getHibernateTemplate().execute(new HibernateCallback<Integer>() {
			public Integer doInHibernate(Session session) throws HibernateException, SQLException {
				Query query = session.createQuery(sql);
				query.setParameterList("ids", ids);
				return query.executeUpdate();
			}
		});
	}
}
